/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */

/**
 * Software License, Version 1.0
 * 
 * Copyright 2004 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
/*
 This file is a clone of GridFTPClient.java form globus with some modification 
 to support GridFTP with NB.

 Original license statement is following:
 This file is licensed under the terms of the Globus Toolkit Public
 License, found at http://www.globus.org/toolkit/download/license.html.
 */
package cgl.narada.gridapps.nbgridftp.gridftpext;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.log4j.Logger;
import org.globus.common.ChainedIOException;
import org.globus.ftp.HostPort;
import org.globus.ftp.exception.FTPReplyParseException;
import org.globus.ftp.exception.ServerException;
import org.globus.ftp.exception.UnexpectedReplyCodeException;
import org.globus.ftp.extended.GridFTPControlChannel;
import org.globus.ftp.extended.GridFTPInputStream;
import org.globus.ftp.extended.GridFTPOutputStream;
import org.globus.ftp.vanilla.Command;
import org.globus.ftp.vanilla.Reply;
import org.globus.gsi.gssapi.GSSConstants;
import org.globus.gsi.gssapi.auth.AuthorizationException;
import org.gridforum.jgss.ExtendedGSSManager;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSManager;
/**
   @author Sang Boem Lim
   $Date$
   $Revision$
 */

public class NBGridFTPControlChannel extends GridFTPControlChannel{
    private static Logger logger = Logger.getLogger(NBGridFTPControlChannel.class.getName());

    public NBGridFTPControlChannel(String host, int port) {

        super(host,port);
    }

    public NBGridFTPControlChannel(InputStream in, OutputStream out) {
        
        super(in, out);
    }

    public void write2Proxy (String msg, boolean finish) {

        try {
            ((NBGridFTPOutputStream)ftpOut).writeToken(msg.getBytes(), finish);
        } catch (IOException e){
            System.out.println("NBGridFTPControlChannel::write2Proxy:"+e);
        }
    }

    public HostPort readFromProxy() {

        try {
            String str = ((NBGridFTPInputStream)rawFtpIn).readToken();
            
            int idx = str.indexOf(':');

            return new HostPort(str.substring(0, idx), 
                                Integer.parseInt(str.substring(idx + 1)));

        } catch (IOException e){
            System.out.println("NBGridFTPControlChannel::readFromProxy:"+e);
            return null;
        }
    }

   /**
     * Performs authentication with specified user credentials.
     *
     * @param credential user credentials to use.
     * @throws IOException on i/o error
     * @throws ServerException on server refusal or faulty server behavior
     */

    public void authenticate( GSSCredential credential )
	    throws IOException, ServerException{
        
        setCredentials( credential );
        
        write(new Command("AUTH", "GSSAPI"));
        
        Reply reply0 = null;
        try {
            reply0 = read();
        } catch (FTPReplyParseException rpe) {
            throw ServerException.
                embedFTPReplyParseException(rpe,
                                            "Received faulty reply to AUTH GSSAPI");
        }
        
        if (! Reply.isPositiveIntermediate(reply0)) {
            close();
            throw ServerException.
                embedUnexpectedReplyCodeException(new UnexpectedReplyCodeException(reply0),   
                                                  "Server refused GSSAPI authentication.");
        }
        
        GSSManager manager = ExtendedGSSManager.getInstance();
        
        GSSContext context = null;
        GridFTPOutputStream gssout = null;
        GridFTPInputStream gssin = null;
        
        try {
            context = manager.createContext(null,
                                            GSSConstants.MECH_OID,
                                            credential,
                                            GSSContext.DEFAULT_LIFETIME);
            context.requestCredDeleg(true);
	        
            gssout = new NBGridFTPOutputStream(ftpOut, context);
            gssin = new NBGridFTPInputStream(rawFtpIn, context);
            
            byte [] inToken = new byte[0];
            byte [] outToken = null;
            
            while( !context.isEstablished() ) {
                
                outToken = context.initSecContext(inToken, 0, inToken.length);
                
                if (outToken != null) {
                    gssout.writeHandshakeToken(outToken);
                }
                
                if (!context.isEstablished()) {
                    inToken = gssin.readHandshakeToken();
                }
            }
            
        } catch (GSSException e) {
            throw new ChainedIOException("Authentication failed", e);
        }
        
        if (this.authorization != null) {
            try {
                this.authorization.authorize(context, 
                                             this.socket.getInetAddress().getHostAddress());
            } catch (AuthorizationException e) {
                throw new ChainedIOException("Authorization failed", e);
            }
        }
        
        // this should be authentication success msg (plain)
        // 234 (ok, no further data required)
        Reply reply1 = null;
        try {
            reply1    = read();
        } catch (FTPReplyParseException rpe) {
            throw ServerException.embedFTPReplyParseException(
                                                              rpe,
                                                              "Received faulty reply to authentication");
            
        }
        
        if ( ! Reply.isPositiveCompletion(reply1)) {
            close();
            throw ServerException.embedUnexpectedReplyCodeException(
                                                                    new UnexpectedReplyCodeException(reply1),
                                                                    "GSSAPI authentication failed.");
        }
        
        // enter secure mode - send MIC commands
        setInputStream(gssin);
        setOutputStream(gssout);
        //from now on, the commands and replies
        //are protected and pass through gsi wrapped socket
        
        write(new Command("USER", ":globus-mapping:"));
        
        Reply reply2 = null;
        try {
            reply2 = read();
        } catch (FTPReplyParseException rpe) {
            throw ServerException.embedFTPReplyParseException(
                                                              rpe,
                                                              "Received faulty reply to USER command");
        }

        
        if (Reply.isPositiveCompletion(reply2) ||
            Reply.isPositiveIntermediate(reply2)) {
            // wu-gsiftp sends intermediate code while
            // gssftp send completion reply code
        } else {
            close();
            throw ServerException.embedUnexpectedReplyCodeException(
                                                                    new UnexpectedReplyCodeException(reply2),
                                                                    "User authorization failed.");
        }
        
        
        write(new Command("PASS", "dummy"));
        
        Reply reply3 = null;
        try {
            reply3=read();
        } catch (FTPReplyParseException rpe) {
            throw ServerException.embedFTPReplyParseException(
                                                              rpe,
                                                              "Received faulty reply to PASS command");
        }
        
        if (!Reply.isPositiveCompletion(reply3)) {
            close();
            throw ServerException.embedUnexpectedReplyCodeException(
                                                                    new UnexpectedReplyCodeException(reply3),
                                                                    "Bad password.");
        }
    }
}

                                     
